#include "chan.h"

#include "sem.h"
#include "mem.h"
#include "assert.h"

#include <string.h>

#define T Chan_T

struct T {
    const void *ptr;
    int *size;
    // send 和 recv 控制读写，而 sync 确保消息传输是同步的 .
    Sem_T send, recv, sync;
};

T Chan_new()
{
    T c;
    NEW(c);
    c->ptr = c->size = NULL;
    Sem_init(&c->send, 1);
    Sem_init(&c->recv, 0);
    Sem_init(&c->sync, 0);
    return c;
}

int Chan_send(T c, const void *ptr, int size)
{
    assert(c);
    assert(ptr);
    assert(size >= 0);

    Sem_wait(&c->send);
    c->ptr = ptr;
    c->size = &size;
    Sem_signal(&c->recv);

    Sem_wait(&c->sync);
    return size;
}

int Chan_receive(T c, void *ptr, int size)
{
    assert(c);
    assert(ptr);
    assert(size >= 0);

    Sem_wait(&c->recv);
    int n = *c->size;
    if (size < n)
        n = size;
    *c->size = n;
    if (n > 0)
        memcpy(ptr, c->ptr, n);
    Sem_signal(&c->sync);
    Sem_signal(&c->send);
    return n;
}

